home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / proxy / proxytrack.c < prev    next >
C/C++ Source or Header  |  2006-04-09  |  47KB  |  1,622 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20. Please visit our Website: http://www.httrack.com
  21. */
  22.  
  23. /* ------------------------------------------------------------ */
  24. /* File: ProxyTrack, httrack cache-based proxy                  */
  25. /* Author: Xavier Roche                                         */
  26. /* ------------------------------------------------------------ */
  27.  
  28.  
  29. /*
  30.  
  31. /\/\/\/\/\/\/\/\/\/\/\/\/\ PENDING WORK /\/\/\/\/\/\/\/\/\/\/\/\/\
  32. - Etag update handling
  33. - Other cache archive handling (.arc)
  34. - Live plug/unplug of archives
  35. - Listing
  36. \/\/\/\/\/\/\/\/\/\/\/\/\/ PENDING WORK \/\/\/\/\/\/\/\/\/\/\/\/\/
  37.  
  38. */
  39.  
  40. /*
  41. Architecture rough draft
  42. Xavier Roche 2005
  43.  
  44. Aim: Building a sub-proxy to be linked with other top level proxies (such as Squid)
  45. Basic design: Classical HTTP/1.0 proxy server, with ICP server support
  46. Internal data design: HTTrack cache indexing in fast hashtables, with 'pluggable' design (add/removal of caches on-the-fly)
  47.  
  48.  
  49. Index structure organization:
  50. -----------------------------
  51.  
  52. foo/hts-cache/new.zip    -----> Index[0]   \
  53. bar/hts-cache/new.zip   -----> Index[1]  >  Central Index Lookup (CIL)
  54. baz/hts-cache/new.zip   -----> Index[2] /
  55. ..            -----> ..
  56.  
  57. Indexes are hashtables with URL (STRING) -> INTEGER lookup.
  58.  
  59. URL -----> CIL            Ask for index ID
  60. URL -----> Index[ID]        Ask for index properties (ZIP cache index)
  61.  
  62.  
  63. Lookup of an entry:
  64. -------------------
  65.  
  66. ID = CIL[URL]
  67. If ID is valid Then
  68.     return SUCCESS
  69. Else
  70.     return FAILURE
  71. EndIf
  72.  
  73.  
  74. Fetching of an entry:
  75. ---------------------
  76.  
  77. RESOURCE = null
  78. ID = CIL[URL]
  79. If ID is valid Then
  80.     OFFSET = Index[ID][URL]
  81.     If OFFSET is valid Then
  82.         RESOURCE = Fetch(ID, OFFSET)
  83.     EndIf
  84. EndIf
  85.  
  86.  
  87. Removal of index N:
  88. -------------------
  89.  
  90. For all entries in Index[N]
  91.     URL(key) -----> Lookup all other caches
  92.         Found: Replace in CIL
  93.         Not Found: Delete entry in CIL
  94. Done
  95. Delete Index[N]
  96.  
  97.  
  98. Adding of index N:
  99. ------------------
  100.  
  101. Build Index[N]
  102. For all entries in Index[N]
  103.     URL(key) -----> Lookup in CIL
  104.         Found: Do nothing if corresponding Cache is newer than this one
  105.         Not Found: Add/Replace entry in CIL
  106. Done
  107.  
  108. Remark: If no cache newer than the added one is found, all entries can be added without any lookup (optim)
  109.  
  110. */
  111.  
  112. /* HTTrack definitions */
  113. #include "htsbase.h"
  114. #include "htsnet.h"
  115. #include "htslib.h"
  116. #include "htsglobal.h"
  117. #include <stdio.h>
  118. #include <stdlib.h>
  119. #include <string.h>
  120. #include <time.h>
  121. #include <fcntl.h>
  122. #if HTS_WIN
  123. #else
  124. #include <arpa/inet.h>
  125. #endif
  126. #ifndef _WIN32
  127. #include <signal.h>
  128. #endif
  129. /* END specific definitions */
  130.  
  131. /* String */
  132. #include "proxystrings.h"
  133.  
  134. /* Network base */
  135. #include "htsbasenet.h"
  136.  
  137. /* dΘfinitions globales */
  138. #include "htsglobal.h"
  139.  
  140. /* htslib */
  141. /*#include "htslib.h"*/
  142.  
  143. /* HTTrack Website Copier Library */
  144. #include "httrack-library.h"
  145.  
  146. /* htsweb */
  147. #include "htsinthash.h"
  148.  
  149. /* ProxyTrack */
  150. #include "proxytrack.h"
  151.  
  152. /* Store manager */
  153. #include "../minizip/mztools.h"
  154. #include "store.h"
  155.  
  156. /* threads */
  157. #ifdef _WIN32
  158. #include <process.h>    /* _beginthread, _endthread */
  159. #else
  160. #include <pthread.h>
  161. #endif
  162.  
  163. /* External references */
  164. // htsErrorCallback htsCallbackErr = NULL;
  165. int htsMemoryFastXfr = 1;    /* fast xfr by default */
  166. void abortLog__fnc(char* msg, char* file, int line);
  167. void abortLog__fnc(char* msg, char* file, int line) {
  168.   FILE* fp = fopen("CRASH.TXT", "wb");
  169.   if (!fp) fp = fopen("/tmp/CRASH.TXT", "wb");
  170.   if (!fp) fp = fopen("C:\\CRASH.TXT", "wb");
  171.   if (!fp) fp = fopen("CRASH.TXT", "wb");
  172.   if (fp) {
  173.     fprintf(fp, "HTTrack " HTTRACK_VERSIONID " closed at '%s', line %d\r\n", file, line);
  174.     fprintf(fp, "Reason:\r\n%s\r\n", msg);
  175.     fflush(fp);
  176.     fclose(fp);
  177.   }
  178. }
  179. // HTSEXT_API t_abortLog abortLog__ = abortLog__fnc;    /* avoid VC++ inlining */
  180. #define webhttrack_lock(A) do{}while(0)
  181.  
  182. /* Static definitions */
  183.  
  184. static int linputsoc(T_SOC soc, char* s, int max) {
  185.   int c;
  186.   int j=0;
  187.   do {
  188.     unsigned char ch;
  189.     if (recv(soc, &ch, 1, 0) == 1) {
  190.       c = ch;
  191.     } else {
  192.       c = EOF;
  193.     }
  194.     if (c!=EOF) {
  195.       switch(c) {
  196.         case 13: break;  // sauter CR
  197.         case 10: c=-1; break;
  198.         case 9: case 12: break;  // sauter ces caractΦres
  199.         default: s[j++]=(char) c; break;
  200.       }
  201.     }
  202.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  203.   s[j]='\0';
  204.   return j;
  205. }
  206.  
  207. static int check_readinput_t(T_SOC soc, int timeout) {
  208.   if (soc != INVALID_SOCKET) {
  209.     fd_set fds;           // poll structures
  210.     struct timeval tv;          // structure for select
  211.     FD_ZERO(&fds);
  212.     FD_SET(soc,&fds);           
  213.     tv.tv_sec=timeout;
  214.     tv.tv_usec=0;
  215.     select((int)(soc + 1),&fds,NULL,NULL,&tv);
  216.     if (FD_ISSET(soc,&fds))
  217.       return 1;
  218.     else
  219.       return 0;
  220.   } else
  221.     return 0;
  222. }
  223.  
  224. static int linputsoc_t(T_SOC soc, char* s, int max, int timeout) {
  225.   if (check_readinput_t(soc, timeout)) {
  226.     return linputsoc(soc, s, max);
  227.   }
  228.   return -1;
  229. }
  230.  
  231. static void unescapeini(char* s, String* tempo) {
  232.   int i;
  233.   char lastc=0;
  234.   for (i=0;i<(int) strlen(s);i++) {
  235.     if (s[i]=='%' && s[i+1]=='%') {
  236.       i++;
  237.       StringAddchar(*tempo, lastc = '%');
  238.     } else if (s[i]=='%') {
  239.       char hc;
  240.       i++;
  241.       hc = (char) ehex(s+i);
  242.       if (!is_retorsep(hc) || !is_retorsep(lastc)) {
  243.         StringAddchar(*tempo, lastc = (char) hc);
  244.       }
  245.       i++;    // sauter 2 caractΦres finalement
  246.     }
  247.     else
  248.       StringAddchar(*tempo, lastc = s[i]);
  249.   }
  250. }
  251.  
  252. static int gethost(const char* hostname, SOCaddr *server, size_t server_size) {
  253.   if (hostname != NULL && *hostname != '\0') {
  254. #if HTS_INET6==0
  255.         /*
  256.         ipV4 resolver
  257.         */
  258.         t_hostent* hp=gethostbyname(hostname);
  259.         if (hp!=NULL) {
  260.             if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  261.                 SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  262.                 return 1;
  263.             }
  264.         }
  265. #else
  266.         /*
  267.         ipV6 resolver
  268.         */
  269.         struct addrinfo* res = NULL;
  270.         struct addrinfo hints;
  271.         memset(&hints, 0, sizeof(hints));
  272. #if 0
  273.         if (IPV6_resolver == 1)        // V4 only (for bogus V6 entries)
  274.             hints.ai_family = PF_INET;
  275.         else if (IPV6_resolver == 2)   // V6 only (for testing V6 only)
  276.             hints.ai_family = PF_INET6;
  277.         else
  278. #endif
  279.         hints.ai_family = PF_UNSPEC;
  280.         hints.ai_socktype = SOCK_STREAM;
  281.         hints.ai_protocol = IPPROTO_TCP;
  282.         if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  283.             if (res) {
  284.                 if ( (res->ai_addr) && (res->ai_addrlen) ) {
  285.                     SOCaddr_copyaddr(*server, server_size, res->ai_addr, res->ai_addrlen);
  286.                     freeaddrinfo(res);
  287.                     return 1;
  288.                 }
  289.             }
  290.         }
  291.         if (res) {
  292.             freeaddrinfo(res);
  293.         }
  294.  
  295. #endif
  296.     }
  297.     return 0;
  298. }
  299.  
  300. static String getip(SOCaddr *server, int serverLen) {
  301.     String s = STRING_EMPTY;
  302. #if HTS_INET6==0
  303.     unsigned int sizeMax = sizeof("999.999.999.999:65535");
  304. #else
  305.     unsigned int sizeMax = sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:65535");
  306. #endif
  307.     char * dotted = malloc(sizeMax + 1);
  308.     unsigned short port  = ntohs(SOCaddr_sinport(*server));
  309.     if (dotted == NULL) {
  310.         CRITICAL("memory exhausted");
  311.         return s;
  312.     }
  313.     SOCaddr_inetntoa(dotted, sizeMax, *server, serverLen);
  314.     sprintf(dotted + strlen(dotted), ":%d", port);
  315.     StringAttach(&s, &dotted);
  316.     return s;
  317. }
  318.  
  319.  
  320. static T_SOC smallserver_init(const char* adr, int port, int family) {
  321.     SOCaddr server;
  322.     size_t server_size = sizeof(server);
  323.  
  324.     memset(&server, 0, sizeof(server));
  325.     SOCaddr_initany(server, server_size); 
  326.   if (gethost(adr, &server, server_size)) {    // host name
  327.         T_SOC soc = INVALID_SOCKET;
  328.     if ( (soc = socket(SOCaddr_sinfamily(server), family, 0)) != INVALID_SOCKET) {
  329.       SOCaddr_initport(server, port);
  330.       if ( bind(soc,(struct sockaddr*) &server, (int)server_size) == 0 ) {
  331.         if (family != SOCK_STREAM 
  332.                     || listen(soc, 10) >=0 ) {
  333.                     return soc;
  334.         } else {
  335. #ifdef _WIN32
  336.           closesocket(soc);
  337. #else
  338.           close(soc);
  339. #endif
  340.           soc=INVALID_SOCKET;
  341.         }
  342.       } else {
  343. #ifdef _WIN32
  344.         closesocket(soc);
  345. #else
  346.         close(soc);
  347. #endif
  348.         soc=INVALID_SOCKET;
  349.       }
  350.     }
  351.   }
  352.   return INVALID_SOCKET;
  353. }
  354.  
  355. static int proxytrack_start(PT_Indexes indexes, T_SOC soc, T_SOC socICP);
  356. int proxytrack_main(char* proxyAddr, int proxyPort, 
  357.                                         char* icpAddr, int icpPort, 
  358.                                         PT_Indexes index) {
  359.   int returncode = 0;
  360.   T_SOC soc = smallserver_init(proxyAddr, proxyPort, SOCK_STREAM);
  361.   T_SOC socICP = smallserver_init(proxyAddr, icpPort, SOCK_DGRAM);
  362.   if (soc != INVALID_SOCKET
  363.         && socICP != INVALID_SOCKET) 
  364.     {
  365.     char url[HTS_URLMAXSIZE*2];
  366.     char method[32];
  367.     char data[32768];
  368.     url[0]=method[0]=data[0]='\0';
  369.     //
  370.     printf("HTTP Proxy installed on %s:%d/\n", proxyAddr, proxyPort);
  371.     printf("ICP Proxy installed on %s:%d/\n", icpAddr, icpPort);
  372. #ifndef _WIN32
  373.     {
  374.       pid_t pid = getpid();
  375.       printf("PID=%d\n", (int)pid);
  376.     }
  377. #endif
  378.     fflush(stdout);
  379.     fflush(stderr);
  380.     //
  381.     if (!proxytrack_start(index, soc, socICP)) {
  382.       fprintf(stderr, "Unable to create the server: %s\n", strerror(errno));
  383. #ifdef _WIN32
  384.       closesocket(soc);
  385. #else
  386.       close(soc);
  387. #endif
  388.       printf("Done\n");
  389.       returncode = 1;
  390.     } else {
  391.       returncode = 0;
  392.     }
  393.   } else {
  394.         fprintf(stderr, "Unable to initialize a temporary server : %s\n", strerror(errno));
  395.     returncode = 1;
  396.   }
  397.   printf("EXITED\n");
  398.   fflush(stdout);
  399.   fflush(stderr);
  400.   return returncode;
  401. }
  402.  
  403. static const char* GetHttpMessage(int statuscode) {
  404.   // Erreurs HTTP, selon RFC
  405.   switch( statuscode) {    
  406.     case 100: return "Continue"; break; 
  407.         case 101: return "Switching Protocols"; break; 
  408.         case 200: return "OK"; break; 
  409.         case 201: return "Created"; break; 
  410.         case 202: return "Accepted"; break; 
  411.         case 203: return "Non-Authoritative Information"; break; 
  412.         case 204: return "No Content"; break; 
  413.         case 205: return "Reset Content"; break; 
  414.         case 206: return "Partial Content"; break; 
  415.         case 207: return "Multi-Status"; break; 
  416.         case 300: return "Multiple Choices"; break; 
  417.         case 301: return "Moved Permanently"; break; 
  418.         case 302: return "Moved Temporarily"; break; 
  419.         case 303: return "See Other"; break; 
  420.         case 304: return "Not Modified"; break; 
  421.         case 305: return "Use Proxy"; break; 
  422.         case 306: return "Undefined 306 error"; break; 
  423.         case 307: return "Temporary Redirect"; break; 
  424.         case 400: return "Bad Request"; break; 
  425.         case 401: return "Unauthorized"; break; 
  426.         case 402: return "Payment Required"; break; 
  427.         case 403: return "Forbidden"; break; 
  428.         case 404: return "Not Found"; break; 
  429.         case 405: return "Method Not Allowed"; break; 
  430.         case 406: return "Not Acceptable"; break; 
  431.         case 407: return "Proxy Authentication Required"; break; 
  432.         case 408: return "Request Time-out"; break; 
  433.         case 409: return "Conflict"; break; 
  434.         case 410: return "Gone"; break; 
  435.         case 411: return "Length Required"; break; 
  436.         case 412: return "Precondition Failed"; break; 
  437.         case 413: return "Request Entity Too Large"; break; 
  438.         case 414: return "Request-URI Too Large"; break; 
  439.         case 415: return "Unsupported Media Type"; break; 
  440.         case 416: return "Requested Range Not Satisfiable"; break; 
  441.         case 417: return "Expectation Failed"; break; 
  442.         case 500: return "Internal Server Error"; break; 
  443.         case 501: return "Not Implemented"; break; 
  444.         case 502: return "Bad Gateway"; break; 
  445.         case 503: return "Service Unavailable"; break; 
  446.         case 504: return "Gateway Time-out"; break; 
  447.         case 505: return "HTTP Version Not Supported"; break; 
  448.         default:    return "Unknown HTTP Error"; break; 
  449.     }
  450. }
  451.  
  452. #ifndef NO_WEBDAV
  453. static void proxytrack_add_DAV_Item(String *item, String *buff,
  454.                                                                         const char* filename,
  455.                                                                         unsigned long int size,
  456.                                                                         time_t timestamp,
  457.                                                                         const char* mime,
  458.                                                                         int isDir,
  459.                                                                         int isRoot,
  460.                                                                         int isDefault) 
  461. {
  462.     struct tm * timetm;
  463.     if (timestamp == (time_t) 0 || timestamp == (time_t) -1) {
  464.         timestamp = time(NULL);
  465.     }
  466.     if ((timetm = gmtime(×tamp)) != NULL) {
  467.         char tms[256 + 1];
  468.         const char * name;
  469.         strftime(tms, 256, "%a, %d %b %Y %H:%M:%S GMT", timetm);        /* Sun, 18 Sep 2005 11:45:45 GMT */
  470.  
  471.         if (mime == NULL || *mime == 0)
  472.             mime = "application/octet-stream";
  473.  
  474.         StringLength(*buff) = 0;
  475.         escapexml(filename, buff);
  476.  
  477.         name = strrchr(StringBuff(*buff), '/');
  478.         if (name != NULL)
  479.             name++;
  480.         if (name == NULL || *name == 0) {
  481.             if (strcmp(mime, "text/html") == 0)
  482.                 name = "Default Document for the Folder.html";
  483.             else
  484.                 name = "Default Document for the Folder";
  485.         }
  486.  
  487.         StringRoom(*item, 1024);
  488.         sprintf(StringBuff(*item),
  489.             "<response xmlns=\"DAV:\">\r\n"
  490.             "<href>/webdav%s%s</href>\r\n"
  491.             "<propstat>\r\n"
  492.             "<prop>\r\n"
  493.             "<displayname>%s</displayname>\r\n"
  494.             "<iscollection>%d</iscollection>\r\n"
  495.             "<haschildren>%d</haschildren>\r\n"
  496.             "<isfolder>%d</isfolder>\r\n"
  497.             "<resourcetype>%s</resourcetype>\r\n"
  498.             "<creationdate>%d-%02d-%02dT%02d:%02d:%02dZ</creationdate>\r\n"
  499.             "<getlastmodified>%s</getlastmodified>\r\n"
  500.             "<supportedlock></supportedlock>\r\n"
  501.             "<lockdiscovery/>\r\n"
  502.             "<getcontenttype>%s</getcontenttype>\r\n"
  503.             "<getcontentlength>%d</getcontentlength>\r\n"
  504.             "<isroot>%d</isroot>\r\n"
  505.             "</prop>\r\n"
  506.             "<status>HTTP/1.1 200 OK</status>\r\n"
  507.             "</propstat>\r\n"
  508.             "</response>\r\n",
  509.             /* */
  510.             ( StringBuff(*buff)[0] == '/' ) ? "" : "/", StringBuff(*buff),
  511.             name,
  512.             isDir ? 1 : 0,
  513.             isDir ? 1 : 0,
  514.             isDir ? 1 : 0,
  515.             isDir ? "<collection/>" : "",
  516.             timetm->tm_year + 1900, timetm->tm_mon + 1, timetm->tm_mday, timetm->tm_hour, timetm->tm_min, timetm->tm_sec,
  517.             tms,
  518.             isDir ? "httpd/unix-directory" : mime,
  519.             (int)size,
  520.             isRoot ? 1 : 0
  521.             );
  522.         StringLength(*item) = (int) strlen(StringBuff(*item));
  523.     }
  524. }
  525.  
  526. /* Convert a RFC822 time to time_t */
  527. time_t get_time_rfc822(const char* s) {
  528.   struct tm result;
  529.   /* */
  530.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  531.   char str[256];
  532.   char* a;
  533.     int i;
  534.   /* */
  535.   int result_mm=-1;
  536.   int result_dd=-1;
  537.   int result_n1=-1;
  538.   int result_n2=-1;
  539.   int result_n3=-1;
  540.   int result_n4=-1;
  541.   /* */
  542.  
  543.   if ((int) strlen(s) > 200)
  544.     return (time_t)0;
  545.     for(i = 0 ; s[i] != 0 ; i++) {
  546.         if (s[i] >= 'A' && s[i] <= 'Z') 
  547.             str[i] = s[i] + ('a' - 'A');
  548.         else
  549.             str[i] = s[i];
  550.     }
  551.     str[i] = 0;
  552.   /* Θliminer :,- */
  553.   while( (a=strchr(str,'-')) ) *a=' ';
  554.   while( (a=strchr(str,':')) ) *a=' ';
  555.   while( (a=strchr(str,',')) ) *a=' ';
  556.   /* tokeniser */
  557.   a=str;
  558.   while(*a) {
  559.     char *first,*last;
  560.     char tok[256];
  561.     /* dΘcouper mot */
  562.     while(*a==' ') a++;   /* sauter espaces */
  563.     first=a;
  564.     while((*a) && (*a!=' ')) a++;
  565.     last=a;
  566.     tok[0]='\0';
  567.     if (first!=last) {
  568.       char* pos;
  569.       strncat(tok,first,(int) (last - first));
  570.       /* analyser */
  571.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  572.         result_mm=((int) (pos - months))/4;
  573.       } else {
  574.         int number;
  575.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  576.           if (result_dd<0)                        /* day always first number */
  577.             result_dd=number;
  578.           else if (result_n1<0)
  579.             result_n1=number;
  580.           else if (result_n2<0)
  581.             result_n2=number;
  582.           else if (result_n3<0)
  583.             result_n3=number;
  584.           else if (result_n4<0)
  585.             result_n4=number;
  586.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  587.       }
  588.     }
  589.   }
  590.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  591.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  592.       result.tm_year=result_n4-1900;
  593.       result.tm_hour=result_n1;
  594.       result.tm_min=result_n2;
  595.       result.tm_sec=max(result_n3,0);
  596.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  597.       result.tm_hour=result_n2;
  598.       result.tm_min=result_n3;
  599.       result.tm_sec=max(result_n4,0);
  600.       if (result_n1<=50)                /* 00 means 2000 */
  601.         result.tm_year=result_n1+100;
  602.       else if (result_n1<1000)          /* 99 means 1999 */
  603.         result.tm_year=result_n1;
  604.       else                              /* 2000 */
  605.         result.tm_year=result_n1-1900;
  606.     }
  607.     result.tm_isdst=0;        /* assume GMT */
  608.     result.tm_yday=-1;        /* don't know */
  609.     result.tm_wday=-1;        /* don't know */
  610.     result.tm_mon=result_mm;
  611.     result.tm_mday=result_dd;
  612.     return mktime(&result);
  613.   }
  614.   return (time_t) 0;
  615. }
  616.  
  617. static PT_Element proxytrack_process_DAV_Request(PT_Indexes indexes, const char * urlFull, int depth) {
  618.     const char * file = jump_protocol_and_auth(urlFull);
  619.     if ( (file = strchr(file, '/')) == NULL)
  620.         return NULL;
  621.  
  622.     if (strncmp(file, "/webdav", 7) != 0) {
  623.         PT_Element elt = PT_ElementNew();
  624.         elt->statuscode = 405;
  625.         strcpy(elt->msg, "Method Not Allowed");
  626.         return elt;
  627.     }
  628.  
  629.     /* Skip /webdav */
  630.     file += 7;
  631.  
  632.     /* */
  633.     {
  634.         PT_Element elt = PT_ElementNew();
  635.         int i, isDir;
  636.         String url = STRING_EMPTY;
  637.         String response = STRING_EMPTY;
  638.         String item = STRING_EMPTY;
  639.         String itemUrl = STRING_EMPTY;
  640.         String buff = STRING_EMPTY;
  641.         StringClear(response);
  642.         StringClear(item);
  643.         StringClear(itemUrl);
  644.         StringClear(buff);
  645.  
  646.         /* Canonize URL */
  647.         StringStrcpy(url, file + ((file[0] == '/') ? 1 : 0));
  648.         if (StringLength(url) > 0) {
  649.             if (StringBuff(url)[StringLength(url) - 1] == '/') {
  650.                 StringBuff(url)[StringLength(url) - 1] = '\0';
  651.                 StringLength(url)--;
  652.             }
  653.         }
  654.  
  655.         /* Form response */
  656.         StringRoom(response, 1024);
  657.         sprintf(StringBuff(response),
  658.             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
  659.             "<multistatus xmlns=\"DAV:\">\r\n");
  660.         StringLength(response) = (int) strlen(StringBuff(response));
  661.         /* */
  662.  
  663.         /* Root */
  664.         StringLength(item) = 0;
  665.         proxytrack_add_DAV_Item(&item, &buff, 
  666.             StringBuff(url), /*size*/0, /*timestamp*/(time_t) 0, /*mime*/NULL, /*isDir*/1, /*isRoot*/1, /*isDefault*/0);
  667.         StringMemcat(response, StringBuff(item), StringLength(item));
  668.  
  669.         /* Childrens (Depth > 0) */
  670.         if (depth > 0) {
  671.             time_t timestampRep = (time_t) -1;
  672.             const char * prefix = StringBuff(url);
  673.             unsigned int prefixLen = (unsigned int) strlen(prefix);
  674.             char ** list = PT_Enumerate(indexes, prefix, 0);
  675.             if (list != NULL) {
  676.                 for(isDir = 1 ; isDir >= 0 ; isDir--) {
  677.                     for(i = 0 ; list[i] != NULL ; i++) {
  678.                         const char * thisUrl = list[i];
  679.                         const char * mimeType = "application/octet-stream";
  680.                         unsigned int thisUrlLen = (unsigned int) strlen(thisUrl);
  681.                         int thisIsDir = (thisUrl[thisUrlLen - 1] == '/') ? 1 : 0;
  682.  
  683.                         /* Item URL */
  684.                         StringRoom(itemUrl, thisUrlLen + prefixLen + sizeof("/webdav/") + 1);
  685.                         StringClear(itemUrl);
  686.                         sprintf(StringBuff(itemUrl), "/%s/%s", prefix, thisUrl);
  687.                         if (!thisIsDir)
  688.                             StringLength(itemUrl) = (int) strlen(StringBuff(itemUrl));
  689.                         else
  690.                             StringLength(itemUrl) = (int) strlen(StringBuff(itemUrl)) - 1;
  691.                         StringBuff(itemUrl)[StringLength(itemUrl)] = '\0';
  692.  
  693.                         if (thisIsDir == isDir) {
  694.                             unsigned long size = 0;
  695.                             time_t timestamp = (time_t) 0;
  696.                             PT_Element file = NULL;
  697.  
  698.                             /* Item stats */
  699.                             if (!isDir) {
  700.                                 file = PT_ReadIndex(indexes, StringBuff(itemUrl) + 1, FETCH_HEADERS);
  701.                                 if (file != NULL && file->statuscode == 200 ) {
  702.                                     size = file->size;
  703.                                     if (file->lastmodified) {
  704.                                         timestamp = get_time_rfc822(file->lastmodified);
  705.                                     }
  706.                                     if (timestamp == (time_t) 0) {
  707.                                         if (timestampRep == (time_t) -1) {
  708.                                             timestampRep = 0;
  709.                                             if (file->indexId != -1) {
  710.                                                 timestampRep = PT_Index_Timestamp(PT_GetIndex(indexes, file->indexId));
  711.                                             }
  712.                                         }
  713.                                         timestamp = timestampRep;
  714.                                     }
  715.                                     if (file->contenttype) {
  716.                                         mimeType = file->contenttype;
  717.                                     }
  718.                                 }
  719.                             }
  720.  
  721.                             /* Add item */
  722.                             StringLength(item) = 0;
  723.                             proxytrack_add_DAV_Item(&item, &buff, 
  724.                                 StringBuff(itemUrl), size, timestamp, mimeType, isDir, /*isRoot*/0, /*isDefault*/(thisUrlLen == 0));
  725.                             StringMemcat(response, StringBuff(item), StringLength(item));
  726.  
  727.                             /* Wipe element */
  728.                             if (file != NULL)
  729.                                 PT_Element_Delete(&file);
  730.                         }
  731.                     }
  732.                 }
  733.                 PT_Enumerate_Delete(&list);
  734.             }  /* items != NULL */
  735.         }        /* Depth > 0 */
  736.  
  737.         /* End of responses */
  738.         StringStrcat(response,
  739.             "</multistatus>\r\n"
  740.             );
  741.  
  742.         StringFree(item);
  743.         StringFree(itemUrl);
  744.         StringFree(url);
  745.         StringFree(buff);
  746.  
  747.         elt->size = StringLength(response);
  748.         elt->adr = StringAcquire(&response);
  749.         elt->statuscode = 207;                                    /* Multi-Status */
  750.         strcpy(elt->charset, "utf-8");
  751.         strcpy(elt->contenttype, "text/xml");
  752.         strcpy(elt->msg, "Multi-Status");
  753.         StringFree(response);
  754.  
  755.         fprintf(stderr, "RESPONSE:\n%s\n", elt->adr);
  756.  
  757.         return elt;
  758.     }
  759.     return NULL;
  760. }
  761. #endif
  762.  
  763. static PT_Element proxytrack_process_HTTP_List(PT_Indexes indexes, const char * url) {
  764.     char ** list = PT_Enumerate(indexes, url, 0);
  765.     if (list != NULL) {
  766.         PT_Element elt = PT_ElementNew();
  767.         int i, isDir;
  768.         String html = STRING_EMPTY;
  769.         StringClear(html);
  770.         StringStrcat(html, 
  771.             "<html>"
  772.             PROXYTRACK_COMMENT_HEADER
  773.             DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES
  774.             "<head>\r\n"
  775.             "<title>ProxyTrack " PROXYTRACK_VERSION " Catalog</title>"
  776.             "</head>\r\n"
  777.             "<body>\r\n"
  778.             "<h3>Directory index:</h3><br />"
  779.             "<br />"
  780.             "<hr>"
  781.             "<tt>[DIR] <a href=\"..\">..</a></tt><br />"
  782.             );
  783.         for(isDir = 1 ; isDir >= 0 ; isDir--) {
  784.             for(i = 0 ; list[i] != NULL ; i++) {
  785.                 char * thisUrl = list[i];
  786.                 unsigned int thisUrlLen = (unsigned int) strlen(thisUrl);
  787.                 int thisIsDir = (thisUrl[thisUrlLen - 1] == '/') ? 1 : 0;
  788.                 if (thisIsDir == isDir) {
  789.                     if (isDir)
  790.                         StringStrcat(html, "<tt>[DIR] ");
  791.                     else
  792.                         StringStrcat(html, "<tt>      ");
  793.                     StringStrcat(html, "<a href=\"");
  794.                     if (isDir) {
  795.                         StringStrcat(html, "http://proxytrack/");
  796.                     }
  797.                     StringStrcat(html, url);
  798.                     StringStrcat(html, list[i]);
  799.                     StringStrcat(html, "\">");
  800.                     StringStrcat(html, list[i]);
  801.                     StringStrcat(html, "</a></tt><br />");
  802.                 }
  803.             }
  804.         }
  805.         StringStrcat(html, 
  806.             "</body>"
  807.             "</html>");
  808.         PT_Enumerate_Delete(&list);
  809.         elt->size = StringLength(html);
  810.         elt->adr = StringAcquire(&html);
  811.         elt->statuscode = 200;
  812.         strcpy(elt->charset, "iso-8859-1");
  813.         strcpy(elt->contenttype, "text/html");
  814.         strcpy(elt->msg, "OK");
  815.         StringFree(html);
  816.         return elt;
  817.     }
  818.     return NULL;
  819. }
  820.  
  821. static void proxytrack_process_HTTP(PT_Indexes indexes, T_SOC soc_c) {
  822.   int timeout=30;
  823.   int retour=0;
  824.     int willexit=0;
  825.     int buffer_size = 32768;
  826.     char * buffer = (char*)malloc(buffer_size);
  827.     int line1Size = 1024;
  828.     char * line1 = (char*)malloc(line1Size);
  829.     int lineSize = 8192;
  830.     char * line = (char*)malloc(lineSize);
  831.     int length = 0;
  832.     int keepAlive = 1;
  833.  
  834.     String url = STRING_EMPTY;
  835.     String urlRedirect = STRING_EMPTY;
  836.     String headers = STRING_EMPTY;
  837.     String output = STRING_EMPTY;
  838.     String host = STRING_EMPTY;
  839.     String localhost = STRING_EMPTY;
  840. #ifndef NO_WEBDAV
  841.     String davHeaders = STRING_EMPTY;
  842.     String davRequest = STRING_EMPTY;
  843. #endif
  844.  
  845.     StringRoom(localhost, 256);
  846.     if (gethostname(StringBuff(localhost), StringCapacity(localhost) - 1) == 0) {
  847.         StringLength(localhost) = (int) strlen(StringBuff(localhost));
  848.     } else {
  849.         StringStrcpy(localhost, "localhost");
  850.     }
  851.  
  852. #ifdef _DEBUG
  853.     Sleep(1000);
  854. #endif
  855.  
  856.     if (buffer == NULL || line == NULL || line1 == NULL) {
  857.         CRITICAL("proxytrack_process_HTTP:memory exhausted");
  858. #if HTS_WIN
  859.         closesocket(soc_c);
  860. #else
  861.         close(soc_c);
  862. #endif
  863.         return ;
  864.     }
  865.  
  866.     do {
  867.         const char* msgError = NULL;
  868.         int msgCode = 0;
  869.         PT_Element element = NULL;
  870.         char* command;
  871.         char* proto;
  872.         char* surl;
  873.         int directHit = 0;
  874.         int headRequest = 0;
  875.         int listRequest = 0;
  876. #ifndef NO_WEBDAV
  877.         int davDepth = 0;
  878. #endif
  879.  
  880.         /* Clear context */
  881.         line[0] = line1[0] = '\0';
  882.         buffer[0] = '\0';
  883.         command = line1;
  884.         StringClear(url);
  885.         StringClear(urlRedirect);
  886.         StringClear(headers);
  887.         StringClear(output);
  888.         StringClear(host);
  889. #ifndef NO_WEBDAV
  890.         StringClear(davHeaders);
  891.         StringClear(davRequest);
  892. #endif
  893.  
  894.         /* line1: "GET http://www.example.com/ HTTP/1.0" */
  895.         if (linputsoc_t(soc_c, line1, line1Size - 2, timeout) > 0
  896.             && ( surl = strchr(line1, ' ') )
  897.             && !(*surl = '\0') 
  898.             && ++surl 
  899.             && (proto = strchr(surl, ' ')) && !(*proto = '\0') && ++proto) 
  900.         {
  901.             /* Flush headers */
  902.             while(linputsoc_t(soc_c, line, lineSize - 2, timeout) > 0
  903.                 && line[0] != 0) 
  904.             {
  905.                 int p;
  906.                 if ((p = strfield(line, "Content-length:"))!=0) {
  907.                     if (sscanf(line+p, "%d", &length) != 1) {
  908.                         msgCode = 500;
  909.                         msgError = "Bad HTTP Content-Length Field";
  910.                         keepAlive = 0;
  911.                         length = 0;
  912.                     }
  913.                 } else if (strcasecmp(line, "Connection: close") == 0) {
  914.                     keepAlive = 0;
  915.                 } else if (strcasecmp(line, "Connection: keep-alive") == 0) {
  916.                     keepAlive = 1;
  917.                 } else if ((p = strfield(line, "Host:"))) {
  918.                     char* chost = line + p;
  919.                     if (*chost == ' ')
  920.                         chost++;
  921.                     StringStrcpy(host, chost);
  922.                 }
  923. #ifndef NO_WEBDAV
  924.                 else if ((p = strfield(line, "Depth: "))) {
  925.                     char* depth = line + p;
  926.                     if (sscanf(depth, "%d", &davDepth) != 1) {
  927.                         davDepth = 0;
  928.                     }
  929.                 }
  930. #endif
  931.             }
  932.  
  933.             /* Flush body */
  934. #ifndef NO_WEBDAV
  935.             if (length > 0) {
  936.                 if (length < 32768) {
  937.                     StringRoom(davRequest, length + 1);
  938.                     if (recv(soc_c, StringBuff(davRequest), length, 0) == length) {
  939.                         StringBuff(davRequest)[length] = 0;
  940.                     } else {
  941.                         msgCode = 500;
  942.                         msgError = "Posted Data Read Error";
  943.                         keepAlive = 0;
  944.                     }
  945.                 } else {
  946.                     msgCode = 500;
  947.                     msgError = "Posted Data Too Large";
  948.                     keepAlive = 0;
  949.                 }
  950.             }
  951. #endif
  952.  
  953.             /* Switch protocol ID */
  954.             if (strcasecmp(command, "post") == 0) {
  955. #ifndef NO_WEBDAV
  956.                 msgCode = 404;
  957. #else
  958.                 msgCode = 501;
  959.                 keepAlive = 0;
  960. #endif
  961.                 msgError = "Proxy Error (POST Request Forbidden)";
  962.             }
  963.             else if (strcasecmp(command, "get") == 0) {
  964.                 headRequest = 0;
  965.             }
  966.             else if (strcasecmp(command, "head") == 0) {
  967.                 headRequest = 1;
  968.             }
  969. #ifndef NO_WEBDAV
  970.             else if (strcasecmp(command, "options") == 0) {
  971.                 const char * options = "GET, HEAD, OPTIONS, POST, PROPFIND, TRACE"
  972.                     ", MKCOL, DELETE, PUT";            /* Not supported */
  973.                 msgCode = 200;
  974.                 StringRoom(headers, 8192);
  975.                 sprintf(StringBuff(headers), 
  976.                     "HTTP/1.1 %d %s\r\n"
  977.                     "DAV: 1, 2\r\n"
  978.                     "MS-Author-Via: DAV\r\n"
  979.                     "Cache-Control: private\r\n"
  980.                     "Allow: %s\r\n",
  981.                     msgCode, GetHttpMessage(msgCode), options);
  982.                 StringLength(headers) = (int) strlen(StringBuff(headers));
  983.             }
  984.             else if (strcasecmp(command, "propfind") == 0) {
  985.                 if (davDepth > 1) {
  986.                     msgCode = 403;
  987.                     msgError = "DAV Depth Limit Forbidden";
  988.                 } else {
  989.                     fprintf(stderr, "DEBUG: DAV-DATA=<%s>\n", StringBuff(davRequest));
  990.                     listRequest = 2;                /* propfind */
  991.                 }
  992.             }
  993.             else if (strcasecmp(command, "mkcol") == 0
  994.                 || strcasecmp(command, "delete") == 0
  995.                 || strcasecmp(command, "put") == 0
  996.                 || strcasecmp(command, "proppatch") == 0
  997.                 || strcasecmp(command, "lock") == 0
  998.                 || strcasecmp(command, "unlock") == 0
  999.                 || strcasecmp(command, "copy") == 0
  1000.                 || strcasecmp(command, "trace") == 0)
  1001.             {
  1002.                 msgCode = 403;
  1003.                 msgError = "Method Forbidden";
  1004.             }
  1005. #endif
  1006.             else {
  1007.                 msgCode = 501;
  1008.                 msgError = "Proxy Error (Unsupported or Unknown HTTP Command Request)";
  1009.                 keepAlive = 0;
  1010.             }
  1011.             if (strcasecmp(proto, "http/1.1") == 0) {
  1012.                 keepAlive = 1;
  1013.             } else if (strcasecmp(proto, "http/1.0") == 0) {
  1014.                 keepAlive = 0;
  1015.             } else {
  1016.                 msgCode = 505;
  1017.                 msgError = "Proxy Error (Unknown HTTP Version)";
  1018.                 keepAlive = 0;
  1019.             }
  1020.  
  1021.             /* Post-process request */
  1022.             if (link_has_authority(surl)) {
  1023.                 const unsigned int prefixLen = sizeof("http://proxytrack/") - 1;
  1024.                 if (strncasecmp(surl, "http://proxytrack/", prefixLen) == 0) {
  1025.                     directHit = 1; /* Another direct hit hack */
  1026.                 }
  1027.                 StringStrcpy(url, surl);
  1028.             } else {
  1029.                 if (StringLength(host) > 0) {
  1030.                     /* Direct hit */
  1031.                     if (
  1032. #ifndef NO_WEBDAV
  1033.                         listRequest != 2
  1034.                         &&
  1035. #endif
  1036.                         strncasecmp(StringBuff(host), StringBuff(localhost), StringLength(localhost)) == 0
  1037.                         && 
  1038.                         (StringBuff(host)[StringLength(localhost)] == '\0'
  1039.                         || StringBuff(host)[StringLength(localhost)] == ':')
  1040.                         && surl[0] == '/'
  1041.                         )
  1042.                     {
  1043.                         const char * toHit = surl + 1;
  1044.                         if (strncmp(toHit, "webdav/", 7) == 0) {
  1045.                             toHit += 7;
  1046.                         }
  1047.                         /* Direct hit */
  1048.                         directHit = 1;
  1049.                         StringStrcpy(url, "");
  1050.                         if (!link_has_authority(toHit))
  1051.                             StringStrcat(url, "http://");
  1052.                         StringStrcat(url, toHit);
  1053.                     } else {
  1054.                         /* Transparent proxy */
  1055.                         StringStrcpy(url, "http://");
  1056.                         StringStrcat(url, StringBuff(host));
  1057.                         StringStrcat(url, surl);
  1058.                     }
  1059.                 } else {
  1060.                     msgCode = 500;
  1061.                     msgError = "Transparent Proxy Error ('Host' HTTP Request Header Field Missing)";
  1062.                     keepAlive = 0;
  1063.                 }
  1064.             }
  1065.  
  1066.             /* Response */
  1067.             if (msgCode == 0) {
  1068.                 if (listRequest == 1) {
  1069.                     element = proxytrack_process_HTTP_List(indexes, StringBuff(url));
  1070.                 }
  1071. #ifndef NO_WEBDAV
  1072.                 else if (listRequest == 2) {
  1073.                     if ((element = proxytrack_process_DAV_Request(indexes, StringBuff(url), davDepth)) != NULL) {
  1074.                         msgCode = element->statuscode;
  1075.                         StringRoom(davHeaders, 1024);
  1076.                         sprintf(StringBuff(davHeaders), 
  1077.                             "DAV: 1, 2\r\n"
  1078.                             "MS-Author-Via: DAV\r\n"
  1079.                             "Cache-Control: private\r\n");
  1080.                         StringLength(davHeaders) = (int) strlen(StringBuff(davHeaders));
  1081.                     }
  1082.                 }
  1083. #endif
  1084.                 else {
  1085.                     element = PT_ReadIndex(indexes, StringBuff(url), FETCH_BODY);
  1086.                 }
  1087.                 if (element == NULL
  1088. #ifndef NO_WEBDAV
  1089.                     && listRequest == 2
  1090. #endif
  1091.                     && StringLength(url) > 0 
  1092.                     && StringBuff(url)[StringLength(url) - 1] == '/'
  1093.                     )
  1094.                 {
  1095.                     element = PT_Index_HTML_BuildRootInfo(indexes);
  1096.                     if (element != NULL) {
  1097.                         element->statuscode = 404;                /* HTML page, but in error */
  1098.                     }
  1099.                 }
  1100.                 if (element != NULL) {
  1101.                     msgCode = element->statuscode;
  1102.                     StringRoom(headers, 8192);
  1103.                     sprintf(StringBuff(headers), 
  1104.                         "HTTP/1.1 %d %s\r\n"
  1105. #ifndef NO_WEBDAV
  1106.                         "%s"
  1107. #endif
  1108.                         "Content-Type: %s%s%s%s\r\n"
  1109.                         "%s%s%s"
  1110.                         "%s%s%s"
  1111.                         "%s%s%s",
  1112.                         /* */
  1113.                         msgCode,
  1114.                         element->msg,
  1115. #ifndef NO_WEBDAV
  1116.                         /* DAV */
  1117.                         StringBuff(davHeaders),
  1118. #endif
  1119.                         /* Content-type: foo; [ charset=bar ] */
  1120.                         element->contenttype,
  1121.                         ( ( element->charset[0]) ? "; charset=\"" : ""),
  1122.                         element->charset,
  1123.                         ( ( element->charset[0]) ? "\"" : ""),
  1124.                         /* location */
  1125.                         ( ( element->location != NULL && element->location[0]) ? "Location: " : ""),
  1126.                         ( ( element->location != NULL && element->location[0]) ? element->location : ""),
  1127.                         ( ( element->location != NULL && element->location[0]) ? "\r\n" : ""),
  1128.                         /* last-modified */
  1129.                         ( ( element->lastmodified[0]) ? "Last-Modified: " : ""),
  1130.                         ( ( element->lastmodified[0]) ? element->lastmodified : ""),
  1131.                         ( ( element->lastmodified[0]) ? "\r\n" : ""),
  1132.                         /* etag */
  1133.                         ( ( element->etag[0]) ? "ETag: " : ""),
  1134.                         ( ( element->etag[0]) ? element->etag : ""),
  1135.                         ( ( element->etag[0]) ? "\r\n" : "")
  1136.                         );
  1137.                     StringLength(headers) = (int) strlen(StringBuff(headers));
  1138.                 } else {
  1139.                     /* No query string, no ending / : check the the <url>/ page */
  1140.                     if (StringLength(url) > 0 && StringBuff(url)[StringLength(url) - 1] != '/' && strchr(StringBuff(url), '?') == NULL) {
  1141.                         StringStrcpy(urlRedirect, StringBuff(url));
  1142.                         StringStrcat(urlRedirect, "/");
  1143.                         if (PT_LookupIndex(indexes, StringBuff(urlRedirect))) {
  1144.                             msgCode = 301;  /* Moved Permanently */
  1145.                             StringRoom(headers, 8192);
  1146.                             sprintf(StringBuff(headers),
  1147.                                 "HTTP/1.1 %d %s\r\n"
  1148.                                 "Content-Type: text/html\r\n"
  1149.                                 "Location: %s\r\n",
  1150.                                 /* */
  1151.                                 msgCode,
  1152.                                 GetHttpMessage(msgCode),
  1153.                                 StringBuff(urlRedirect)
  1154.                                 );
  1155.                             StringLength(headers) = (int) strlen(StringBuff(headers));
  1156.                             /* */
  1157.                             StringRoom(output, 1024 + sizeof(PROXYTRACK_COMMENT_HEADER) + sizeof(DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES));
  1158.                             sprintf(StringBuff(output), 
  1159.                                 "<html>"
  1160.                                 PROXYTRACK_COMMENT_HEADER
  1161.                                 DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES
  1162.                                 "<head>"
  1163.                                 "<title>ProxyTrack - Page has moved</title>"
  1164.                                 "</head>\r\n"
  1165.                                 "<body>"
  1166.                                 "<h3>The correct location is:</h3><br />"
  1167.                                 "<b><a href=\"%s\">%s</a></b><br />"
  1168.                                 "<br />"
  1169.                                 "<br />\r\n"
  1170.                                 "<i>Generated by ProxyTrack " PROXYTRACK_VERSION ", (C) Xavier Roche and other contributors</i>"
  1171.                                 "\r\n"
  1172.                                 "</body>"
  1173.                                 "</header>",
  1174.                                 StringBuff(urlRedirect),
  1175.                                 StringBuff(urlRedirect));
  1176.                             StringLength(output) = (int) strlen(StringBuff(output));
  1177.                         }
  1178.                     }
  1179.                     if (msgCode == 0) {
  1180.                         msgCode = 404;
  1181.                         msgError = "Not Found in this cache";
  1182.                     }
  1183.                 }
  1184.             }
  1185.         } else {
  1186.             msgCode = 500;
  1187.             msgError = "Server Error";
  1188.             keepAlive = 0;
  1189.         }
  1190.         if (StringLength(headers) == 0) {
  1191.             if (msgCode == 0) {
  1192.                 msgCode = 500;
  1193.                 msgError = "Internal Proxy Error";
  1194.             } else if (msgError == NULL) {
  1195.                 msgError = GetHttpMessage(msgCode);
  1196.             }
  1197.             StringRoom(headers, 256);
  1198.             sprintf(StringBuff(headers), 
  1199.                 "HTTP/1.1 %d %s\r\n"
  1200.                 "Content-type: text/html\r\n",
  1201.                 msgCode,
  1202.                 msgError);
  1203.             StringLength(headers) = (int) strlen(StringBuff(headers));
  1204.             StringRoom(output, 1024 + sizeof(PROXYTRACK_COMMENT_HEADER) + sizeof(DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES));
  1205.             sprintf(StringBuff(output), 
  1206.                 "<html>"
  1207.                 PROXYTRACK_COMMENT_HEADER
  1208.                 DISABLE_IE_FRIENDLY_HTTP_ERROR_MESSAGES
  1209.                 "<head>"
  1210.                 "<title>ProxyTrack - HTTP Proxy Error %d</title>"
  1211.                 "</head>\r\n"
  1212.                 "<body>"
  1213.                 "<h3>A proxy error has occured while processing the request.</h3><br />"
  1214.                 "<b>Error HTTP %d: <i>%s</i></b><br />"
  1215.                 "<br />"
  1216.                 "<br />\r\n"
  1217.                 "<i>Generated by ProxyTrack " PROXYTRACK_VERSION ", (C) Xavier Roche and other contributors</i>"
  1218.                 "\r\n"
  1219.                 "</body>"
  1220.                 "</html>",
  1221.                 msgCode,
  1222.                 msgCode,
  1223.                 msgError);
  1224.             StringLength(output) = (int) strlen(StringBuff(output));
  1225.         }
  1226.         {
  1227.             char tmp[20 + 1]; /* 2^64 = 18446744073709551616 */
  1228.             unsigned int dataSize = 0;
  1229.             if (!headRequest) {
  1230.                 dataSize = StringLength(output);
  1231.                 if (dataSize == 0 && element != NULL) {
  1232.                     dataSize = element->size;
  1233.                 }
  1234.             }
  1235.             sprintf(tmp, "%d", (int) dataSize);
  1236.             StringStrcat(headers, "Content-length: ");
  1237.             StringStrcat(headers, tmp);
  1238.             StringStrcat(headers, "\r\n");
  1239.         }
  1240.         if (keepAlive) {
  1241.             StringStrcat(headers, 
  1242.                 "Connection: Keep-Alive\r\n"
  1243.                 "Proxy-Connection: Keep-Alive\r\n");
  1244.         } else {
  1245.             StringStrcat(headers, 
  1246.                 "Connection: Close\r\n"
  1247.                 "Proxy-Connection: Close\r\n");
  1248.         }
  1249.         if (msgCode != 500)
  1250.             StringStrcat(headers, "X-Cache: HIT from ");
  1251.         else
  1252.             StringStrcat(headers, "X-Cache: MISS from ");
  1253.         StringStrcat(headers, StringBuff(localhost));
  1254.         StringStrcat(headers, "\r\n");
  1255.  
  1256.         /* Logging */
  1257.         {
  1258.             const char * contentType = "text/html";
  1259.             unsigned long int size = StringLength(output) ? StringLength(output) : ( element ? element->size : 0 );
  1260.             /* */
  1261.             String ip = STRING_EMPTY;
  1262.             SOCaddr serverClient;
  1263.             int lenServerClient = (int) sizeof(serverClient);
  1264.             memset(&serverClient, 0, sizeof(serverClient));
  1265.             if (getsockname(soc_c, (struct sockaddr*) &serverClient, &lenServerClient) == 0) {
  1266.                 ip = getip(&serverClient, lenServerClient);
  1267.             } else {
  1268.                 StringStrcpy(ip, "unknown");
  1269.             }
  1270.             if (element != NULL && element->contenttype[0] != '\0') {
  1271.                 contentType = element->contenttype;
  1272.             }
  1273.             LOG("HTTP %s %d %d %s %s %s" _ StringBuff(ip) _ msgCode _ (int)size _ command _ StringBuff(url) _ contentType);
  1274.             StringFree(ip);
  1275.         }
  1276.  
  1277.         /* Send reply */
  1278.         StringStrcat(headers, "Server: ProxyTrack " PROXYTRACK_VERSION " (HTTrack " HTTRACK_VERSIONID ")\r\n");
  1279.         StringStrcat(headers, "\r\n");            /* Headers separator */
  1280.         if (send(soc_c, StringBuff(headers), StringLength(headers), 0) != StringLength(headers)
  1281.             || ( !headRequest && StringLength(output) > 0 && send(soc_c, StringBuff(output), StringLength(output), 0) != StringLength(output))
  1282.             || ( !headRequest && StringLength(output) == 0 && element != NULL && element->adr != NULL && send(soc_c, element->adr, element->size, 0) != element->size)
  1283.             )
  1284.         {
  1285.             keepAlive = 0;        /* Error, abort connection */
  1286.         }
  1287.         PT_Element_Delete(&element);
  1288.  
  1289.         /* Shutdown (FIN) and wait until confirmed */
  1290.         if (!keepAlive) {
  1291.             char c;
  1292. #ifdef _WIN32
  1293.             shutdown(soc_c, SD_SEND);
  1294. #else
  1295.             shutdown(soc_c, 1);
  1296. #endif
  1297.             while(recv(soc_c, ((char*)&c), 1, 0) > 0);
  1298.         }
  1299.     } while(keepAlive);
  1300.  
  1301. #if HTS_WIN
  1302.     closesocket(soc_c);
  1303. #else
  1304.     close(soc_c);
  1305. #endif
  1306.  
  1307.     StringFree(url);
  1308.     StringFree(urlRedirect);
  1309.     StringFree(headers);
  1310.     StringFree(output);
  1311.     StringFree(host);
  1312.  
  1313.     if (buffer)
  1314.         free(buffer);
  1315. }
  1316.  
  1317. #ifdef _WIN32
  1318. #define PTHREAD_RETURN
  1319. #define PTHREAD_TYPE void
  1320. #define PTHREAD_TYPE_FNC __cdecl
  1321. #else
  1322. #define PTHREAD_RETURN NULL
  1323. #define PTHREAD_TYPE void*
  1324. #define PTHREAD_TYPE_FNC
  1325. #endif
  1326.  
  1327. /* Generic threaded function start */
  1328. static int startThread(PTHREAD_TYPE (PTHREAD_TYPE_FNC * funct)(void* ),
  1329.                                              void* param) 
  1330. {
  1331.     if (param != NULL) {
  1332. #ifdef _WIN32
  1333.         if (_beginthread(funct, 0, param) == -1) {
  1334.             free(param);
  1335.             return 0;
  1336.         }
  1337.         return 1;
  1338. #else
  1339.         pthread_t handle = 0;
  1340.         int retcode;
  1341.         retcode = pthread_create(&handle, NULL, funct, param);
  1342.         if (retcode != 0) {   /* error */
  1343.             free(param);
  1344.             return 0;
  1345.         } else {
  1346.             /* detach the thread from the main process so that is can be independent */
  1347.             pthread_detach(handle);
  1348.             return 1;
  1349.         }
  1350. #endif
  1351.     } else {
  1352.         return 0;
  1353.     }
  1354. }
  1355.  
  1356. /* Generic socket/index structure */
  1357. typedef struct proxytrack_process_th_p {
  1358.     T_SOC soc_c;
  1359.     PT_Indexes indexes;
  1360.     void (*process)(PT_Indexes indexes, T_SOC soc_c);
  1361. } proxytrack_process_th_p;
  1362.  
  1363. /* Generic socket/index function stub */
  1364. static PTHREAD_TYPE PTHREAD_TYPE_FNC proxytrack_process_th(void* param_) {
  1365.     proxytrack_process_th_p *param = (proxytrack_process_th_p *) param_;
  1366.     T_SOC soc_c = param->soc_c;
  1367.     PT_Indexes indexes = param->indexes;
  1368.     void (*process)(PT_Indexes indexes, T_SOC soc_c) = param->process;
  1369.     free(param);
  1370.     process(indexes, soc_c);
  1371.     return PTHREAD_RETURN ;
  1372. }
  1373.  
  1374. /* Process generic socket/index operation */
  1375. static int proxytrack_process_generic(void (*process)(PT_Indexes indexes, T_SOC soc_c),
  1376.                                                                             PT_Indexes indexes, T_SOC soc_c) 
  1377. {
  1378.     proxytrack_process_th_p *param = calloc(sizeof(proxytrack_process_th_p), 1);
  1379.     if (param != NULL) {
  1380.         param->soc_c = soc_c;
  1381.         param->indexes = indexes;
  1382.         param->process = process;
  1383.         return startThread(proxytrack_process_th, param);
  1384.     } else {
  1385.         CRITICAL("proxytrack_process_generic:Memory exhausted");
  1386.         return 0;
  1387.     }
  1388.     return 0;
  1389. }
  1390.  
  1391. /* Process HTTP proxy requests */
  1392. static int proxytrack_process_HTTP_threaded(PT_Indexes indexes, T_SOC soc) {
  1393.     return proxytrack_process_generic(proxytrack_process_HTTP, indexes, soc);
  1394. }
  1395.  
  1396. /* HTTP Server */
  1397. static int proxytrack_start_HTTP(PT_Indexes indexes, T_SOC soc) {
  1398.     while(soc != INVALID_SOCKET) {
  1399.     T_SOC soc_c;
  1400.         struct sockaddr clientAddr;
  1401.         int clientAddrLen = sizeof(struct sockaddr);
  1402.         memset(&clientAddr, 0, sizeof(clientAddr));
  1403.         if ( (soc_c = accept(soc, &clientAddr, &clientAddrLen)) != INVALID_SOCKET) {
  1404.             if (!proxytrack_process_HTTP_threaded(indexes, soc_c)) {
  1405.                 CRITICAL("proxytrack_start_HTTP::Can not fork a thread");
  1406.             }
  1407.         }
  1408.     }
  1409.     if (soc != INVALID_SOCKET) {
  1410. #ifdef _WIN32
  1411.         closesocket(soc);
  1412. #else
  1413.         close(soc);
  1414. #endif
  1415.     }
  1416.     return 1;
  1417. }
  1418.  
  1419. /* Network order is big endian */
  1420. #define READ_NET16(buffer) ( ( ((unsigned char*)buffer)[0] << 8 ) + ((unsigned char*)buffer)[1] )
  1421. #define READ_NET32(buffer) ( ( READ_NET16(buffer) << 16 ) + READ_NET16(((unsigned char*)buffer) + 2) )
  1422. #define WRITE_NET8(buffer, value) do { \
  1423.     ((unsigned char*)buffer)[0] = (unsigned char)(value); \
  1424. } while(0)
  1425. #define WRITE_NET16(buffer, value) do { \
  1426.     ((unsigned char*)buffer)[0] = (((unsigned short)(value)) >> 8) & 0xff; \
  1427.     ((unsigned char*)buffer)[1] = ((unsigned short)(value)) & 0xff; \
  1428. } while(0)
  1429. #define WRITE_NET32(buffer, value) do { \
  1430.     WRITE_NET16(buffer, ( ((unsigned int)(value)) >> 16 ) & 0xffff); \
  1431.     WRITE_NET16(((unsigned char*)buffer) + 2, ( ((unsigned int)(value)) ) & 0xffff); \
  1432. } while(0)
  1433.  
  1434. static int ICP_reply(struct sockaddr * clientAddr,
  1435.                                          int clientAddrLen,
  1436.                                          T_SOC soc,
  1437.                                          /* */
  1438.                                          unsigned char  Opcode,
  1439.                                          unsigned char  Version,
  1440.                                          unsigned short Message_Length,
  1441.                                          unsigned int   Request_Number,
  1442.                                          unsigned int   Options,
  1443.                                          unsigned int   Option_Data,
  1444.                                          unsigned int   Sender_Host_Address,
  1445.                                          unsigned char *Message
  1446.                                          ) 
  1447. {
  1448.     int ret = 0;
  1449.     unsigned long int BufferSize;
  1450.     unsigned char * buffer;
  1451.     if (Message_Length == 0 && Message != NULL)                                /* We have to get the message size */
  1452.         Message_Length  = (unsigned int) strlen(Message) + 1;        /* NULL terminated */
  1453.     BufferSize = 20 + Message_Length;
  1454.     buffer = malloc(BufferSize);
  1455.     if (buffer != NULL) {
  1456.         WRITE_NET8(&buffer[0], Opcode);
  1457.         WRITE_NET8(&buffer[1], Version);
  1458.         WRITE_NET16(&buffer[2], Message_Length);
  1459.         WRITE_NET32(&buffer[4], Request_Number);
  1460.         WRITE_NET32(&buffer[8], Options);
  1461.         WRITE_NET32(&buffer[12], Option_Data);
  1462.         WRITE_NET32(&buffer[16], Sender_Host_Address);
  1463.         if (Message != NULL && Message_Length > 0) {
  1464.             memcpy(buffer + 20, Message, Message_Length);
  1465.         }
  1466.         if (sendto(soc, buffer, BufferSize, 0, clientAddr, clientAddrLen) == BufferSize) {
  1467.             ret = 1;
  1468.         }
  1469.         free(buffer);
  1470.     }
  1471.     return ret;
  1472. }
  1473.  
  1474. /* ICP Server */
  1475. static int proxytrack_start_ICP(PT_Indexes indexes, T_SOC soc) {
  1476.     /* "ICP messages MUST not exceed 16,384 octets in length." (RFC2186) */
  1477.     int bufferSize = 16384;
  1478.     unsigned char * buffer = (unsigned char*) malloc(bufferSize + 1);
  1479.     if (buffer == NULL) {
  1480.         CRITICAL("proxytrack_start_ICP:memory exhausted");
  1481. #ifdef _WIN32
  1482.         closesocket(soc);
  1483. #else
  1484.         close(soc);
  1485. #endif
  1486.         return -1;
  1487.     }
  1488.     while(soc != INVALID_SOCKET) {
  1489.         struct sockaddr clientAddr;
  1490.         int clientAddrLen = sizeof(struct sockaddr);
  1491.         int n;
  1492.         memset(&clientAddr, 0, sizeof(clientAddr));
  1493.         n = recvfrom(soc, (char*)buffer, bufferSize, 0, &clientAddr, &clientAddrLen);
  1494.         if (n != -1) {
  1495.             const char * LogRequest = "ERROR";
  1496.             const char * LogReply = "ERROR";
  1497.             unsigned char * UrlRequest = NULL;
  1498.             if (n >= 20) {
  1499.                 enum {
  1500.                     ICP_OP_MIN = 0,
  1501.                     ICP_OP_INVALID = 0,
  1502.                     ICP_OP_QUERY = 1,
  1503.                     ICP_OP_HIT = 2,
  1504.                     ICP_OP_MISS = 3,
  1505.                     ICP_OP_ERR = 4,
  1506.                     ICP_OP_SECHO = 10,
  1507.                     ICP_OP_DECHO = 11,
  1508.                     ICP_OP_MISS_NOFETCH = 21,
  1509.                     ICP_OP_DENIED = 22,
  1510.                     ICP_OP_HIT_OBJ = 23,
  1511.                     ICP_OP_MAX = ICP_OP_HIT_OBJ
  1512.                 };
  1513.                 unsigned char  Opcode = buffer[0];
  1514.                 unsigned char  Version = buffer[1];
  1515.                 unsigned short Message_Length = READ_NET16(&buffer[2]);
  1516.                 unsigned int   Request_Number = READ_NET32(&buffer[4]);   /* Session ID */
  1517.                 unsigned int   Options = READ_NET32(&buffer[8]);
  1518.                 unsigned int   Option_Data = READ_NET32(&buffer[12]);     /* ICP_FLAG_SRC_RTT */
  1519.                 unsigned int   Sender_Host_Address = READ_NET32(&buffer[16]);        /* ignored */
  1520.                 unsigned char* Payload = &buffer[20];
  1521.                 buffer[bufferSize] = '\0';                                                              /* Ensure payload is NULL terminated */
  1522.                 if (Message_Length <= bufferSize - 20) {
  1523.                     if (Opcode >= ICP_OP_MIN && Opcode <= ICP_OP_MAX) {
  1524.                         if (Version == 2) {
  1525.                             switch(Opcode) {
  1526.                             case ICP_OP_QUERY:
  1527.                                 {
  1528.                                     unsigned int UrlRequestSize;
  1529.                                     UrlRequest = &Payload[4];
  1530.                                     UrlRequestSize = (unsigned int)strlen((char*)UrlRequest);
  1531.                                     LogRequest = "ICP_OP_QUERY";
  1532.                                     if (indexes == NULL) {
  1533.                                         ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_DENIED, Version, 0, Request_Number, 0, 0, 0, UrlRequest);
  1534.                                         LogReply = "ICP_OP_DENIED";
  1535.                                     } else if (PT_LookupIndex(indexes, UrlRequest)) {
  1536.                                         ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_HIT, Version, 0, Request_Number, 0, 0, 0, UrlRequest);
  1537.                                         LogReply = "ICP_OP_HIT";
  1538.                                     } else {
  1539.                                         if (UrlRequestSize > 0 && UrlRequest[UrlRequestSize - 1] != '/' && strchr(UrlRequest, '?') == NULL) {
  1540.                                             char * UrlRedirect = malloc(UrlRequestSize + 1 + 1);
  1541.                                             if (UrlRedirect != NULL) {
  1542.                                                 sprintf(UrlRedirect, "%s/", UrlRequest);
  1543.                                                 if (PT_LookupIndex(indexes, UrlRedirect)) {            /* We'll generate a redirect */
  1544.                                                     ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_HIT, Version, 0, Request_Number, 0, 0, 0, UrlRequest);
  1545.                                                     LogReply = "ICP_OP_HIT";
  1546.                                                     free(UrlRedirect);
  1547.                                                     break;
  1548.                                                 }
  1549.                                                 free(UrlRedirect);
  1550.                                             }
  1551.                                         }
  1552.                                         /* We won't retrive the cache MISS online, no way! */
  1553.                                         ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_MISS_NOFETCH, Version, 0, Request_Number, 0, 0, 0, UrlRequest);
  1554.                                         LogReply = "ICP_OP_MISS_NOFETCH";
  1555.                                     }
  1556.                                 }
  1557.                                 break;
  1558.                             case ICP_OP_SECHO:
  1559.                                 {
  1560.                                     UrlRequest = &Payload[4];
  1561.                                     LogRequest = "ICP_OP_QUERY";
  1562.                                     LogReply = "ICP_OP_QUERY";
  1563.                                     ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_SECHO, Version, 0, Request_Number, 0, 0, 0, UrlRequest);
  1564.                                 }
  1565.                                 break;
  1566.                             default:
  1567.                                 LogRequest = "NOTIMPLEMENTED";
  1568.                                 LogReply = "ICP_OP_ERR";
  1569.                                 ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_ERR, Version, 0, Request_Number, 0, 0, 0, NULL);
  1570.                                 break;
  1571.                             }
  1572.                         } else {
  1573.                             ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_ERR, 2, 0, Request_Number, 0, 0, 0, NULL);
  1574.                         }
  1575.                     } /* Ignored (RFC2186) */
  1576.                 } else {
  1577.                     ICP_reply(&clientAddr, clientAddrLen, soc, ICP_OP_ERR, Version, 0, Request_Number, 0, 0, 0, NULL);
  1578.                 }
  1579.             }
  1580.  
  1581.             /* Logging */
  1582.             {
  1583.                 String ip = STRING_EMPTY;
  1584.                 SOCaddr serverClient;
  1585.                 int lenServerClient = (int) sizeof(serverClient);
  1586.                 SOCaddr_copyaddr(serverClient, lenServerClient, &clientAddr, clientAddrLen);
  1587.                 if (lenServerClient > 0) {
  1588.                     ip = getip(&serverClient, lenServerClient);
  1589.                 } else {
  1590.                     StringStrcpy(ip, "unknown");
  1591.                 }
  1592.                 LOG("ICP %s %s/%s %s" _ StringBuff(ip) _ LogRequest _ LogReply _ (UrlRequest ? UrlRequest : "-") );
  1593.                 StringFree(ip);
  1594.             }
  1595.  
  1596.         }
  1597.     }
  1598.     if (soc != INVALID_SOCKET) {
  1599. #ifdef _WIN32
  1600.         closesocket(soc);
  1601. #else
  1602.         close(soc);
  1603. #endif
  1604.     }
  1605.     free(buffer);
  1606.     return 1;
  1607. }
  1608.  
  1609. static int proxytrack_start(PT_Indexes indexes, T_SOC soc, T_SOC socICP) {
  1610.     int ret = 1;
  1611.     if (proxytrack_process_generic(proxytrack_start_ICP, indexes, socICP)) {
  1612.         //if (!proxytrack_process_generic(proxytrack_start_HTTP, indexes, soc))
  1613.         if (!proxytrack_start_HTTP(indexes, soc)) {
  1614.             ret = 0;
  1615.         }
  1616.     } else {
  1617.         ret = 0;
  1618.     }
  1619.     return ret;
  1620. }
  1621.  
  1622.